/*
 * Copyright (c) 2024-2025 iSOFT INFRASTRUCTURE SOFTWARE CO., LTD.
 * easyAda is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#ifndef __UAPI_IPC_BUFFER_H__
#define __UAPI_IPC_BUFFER_H__

#include <plat/config.h>
#include <stdlib/stddef.h>
#include <stdlib/stdint.h>

#include <plat/config.h>
#include <stdlib/stddef.h>
#include <stdlib/stdint.h>

#include "bootinfo.h"
#include "fault.h"

#define OS_ALIGNED(x) __attribute__((aligned(x)))

#define IPC_MAX_MSGWORDS (256)

#define UTCB_MAGIC (0x21768613)    // "utcb"

typedef struct ipcbuffer {
    size_t tag;
    // valid message words
    // the first 2 words of msgs will be transferred through registers
    size_t msgs[IPC_MAX_MSGWORDS];

    int32_t  errcode;               // errno
    uint64_t ep_sender_aid;         // ep发送者的进程指数
    cptr_t   ep_sender_cptr;        // ep发送者的线程
    uint64_t retval;                // 加入其他线程后的返回值
    void *(*user_entry)(void *);    // The actual entry of the user
} OS_ALIGNED(sizeof(uint64_t) * 2) ipcbuffer_t;

static inline uint64_t msgtag_get_len(uint64_t tag)
{
    return (tag >> 16) & 0xffUL;
}

static inline uint64_t msgtag_get_info(uint64_t tag)
{
    return tag & 0xffffUL;
}

static inline uint64_t msgtag_set_info(uint64_t tag, uint16_t info)
{
    tag &= ~(0xffffUL);
    tag |= info;

    return tag;
}

#define msgtag_get_op(tag)     msgtag_get_info(tag)
#define msgtag_get_id(tag)     msgtag_get_info(tag)
#define msgtag_set_op(tag, op) msgtag_set_info(tag, op)
#define msgtag_set_id(tag, op) msgtag_set_info(tag, op)

static inline uint64_t msgtag_get_extra(uint64_t tag)
{
    return (tag >> 24) & 0xffUL;
}

static inline uint64_t msgtag_set_extra(uint64_t tag, uint8_t extra)
{
    tag &= ~(0xff000000UL);
    tag |= extra << 24;

    return tag;
}

#define TOLONGS(x) (((sizeof(x) + sizeof(size_t) - 1UL) / sizeof(size_t)) + 2UL)

/*| (8bit) | (8bit) | (16bit) |*/
/*| extra  | len    | id_op   |*/
static inline uint64_t msgtag_make(uint8_t len, uint16_t id_op, uint8_t extra)
{
    return (extra << 24) | (len << 16) | id_op;
}

/**
 * @brief 从ipcbuffer获得系统调用传参地址，用于大部分情况的ipc传参
 *        尽量不直接手动取偏移，ipc格式在uapi/ipcops.h里
 * @param buf 指定ipcbuffer
 */
static inline void *ipcbuffer_get_op_struct(ipcbuffer_t *buf)
{
    return buf->msgs + 2;
}

static inline uint64_t *ipcbuffer_get_msgs(ipcbuffer_t *buf)
{
    return buf->msgs;
}

static inline void ipcbuffer_set_msgs(ipcbuffer_t *buf, uint32_t index, uint64_t value)
{
    buf->msgs[index] = value;
}

static inline uint8_t ipcbuffer_get_msglen(ipcbuffer_t *buf)
{
    return msgtag_get_len(buf->tag);
}

static inline uint16_t ipcbuffer_get_id(ipcbuffer_t *buf)
{
    return msgtag_get_id(buf->tag);
}

static inline uint64_t ipcbuffer_get_tag(ipcbuffer_t *buf)
{
    return buf->tag;
}

static inline void ipcbuffer_set_tag(ipcbuffer_t *buf, uint8_t msglen, uint16_t info, uint8_t extra)
{
    buf->tag = msgtag_make(msglen, info, extra);
}

static inline void ipcbuffer_save(ipcbuffer_t *buf, uint64_t tag, uint64_t m0, uint64_t m1)
{
    buf->tag     = tag;
    buf->msgs[0] = m0;
    buf->msgs[1] = m1;
}

#endif
